数据结构与算法 - 最短路径和最小生成树(Day4)
最短路径
在带权图G=(V.E)中, 若顶点Vi, Vj是图G的两个顶点, 从顶点Vi到Vj的路径长度定义为路径上各条边的权值之和. 从顶点Vi到Vj可能有多条路径, 其中路径长度最小的称为顶点Vi到Vj的最短路径
最短路问题
- 求从某个顶点到其他顶点的最短路径
- dijkstra算法
- Bellman-ford算法
- SPFA算法
- 求图中每一对顶点间的最短路径
- 弗洛伊德算法(Floyed)
- 求从某个顶点到其他顶点的最短路径
对于无权图, 可把每条边的权值设置为1处理.
算法
弗洛伊德算法
- 若图中任意两点之间只允许编号<=k-1的点作为中转时的最短路已知
- 可依此推出任意两点之间只允许以编号<=k的点做中转的最短路
1
2if(d[i][k] + d[k][j] < d[i][j]) //d[i][k]的路径长度和d[k][j]的路径长度之和小于ij之间路径
d[i][j] = d[i][k] + d[k][j];//升级ij路径为更短的1
2
3
4
5
6
7
8
9
10//算法核心
for(int k = 1; k<=n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1;j <= n; i++)
if(d[i][k] + d[k][j] < d[i][j])
d[i][j] = d[i][k] + d[k][j];
//初始化条件
d[i][i] = 0;
d[i][j] = 边权(若i,j之间直接相连);
d[i][j] = ∞ (若i,j无直接相连的边);Dijkstra算法
求一个顶点到其余各定点的最短路径
算法思路
- 设起点为s, dis[v]表示从s到v的最短路径, path[v]为v的前驱节点, 用来输出路径
- 初始化: dis[v]=∞(v≠s); dis[s]=0; path[s]=0;
- for i = 1 to n
- 在没有被标记的点找一个顶点u使得dis[u]是最小的
- u标记为已确定的最短路径
- 循环: 与u相连的每个未确定最短路径的顶点v
- 若dis[u]+Weight(u,v) < dis[v]
- dis[v] = dis[u] + Weight(u,v);
- path[v] = u;
- 若dis[u]+Weight(u,v) < dis[v]
使用条件
- 不存在边权为负数的情况(不存在负权边)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29void dijkstra(int s){
for(int i = 1;i<=n;i++){ //初始化
d[i] = a[s][i]; //d[i]初始化成i到s的长度
f[i] = false; //f[i]标志位初始化为false
path[i] = s; //i的前驱结点为起点
}
f[s] = true; //标记起点
for(int i = 2;i<=n;i++){
int mind = inf; //inf = 0x7f
int k = 0; //记录准备标记的点
for(int j = 1;j<=n;j++){
if(!f[j] && (d[j] < mind)){
mind = d[j]; k = j;
}
if(mind == inf)
break;//无连接到j的点, 无法更新
f[k] = true;
for(int j = 1; j<=n; j++)
if((!f[j]) && (d[k] + a[k][j] < d[j])){
d[j] = d[k] + a[k][j];
path[j] = k;
}
}
}
}
最小生成树
- N个点用N-1条边连接成一个连通块, 形成的图形只可能是树.
- 一个有N个点的图, 边一定大于等于N-1条
- 图的最小生成树就是在这些边中选择N-1条, 连接所有的N个点. 这N-1条边的边权之和是所有方案中最小的
- 生成算法
- Prim算法
- 待续
- Kruskal算法
- 待续
- Prim算法